#--
# Copyright (c) 2007 Mathew Abonyi
# Please read LICENSE document for more information.
#++

module Retrospectiva
  module Extension
    module SCMTicketUpdate

      # The Parser class extracts the id and properties for a ticket reference,
      # and the comment which accompanies it, and returns it in a hash to be
      # used by Update to create a TicketReference instance.
      class Parser

        class << self

          TICKET_REF = /\[\#(\d+)/

          TICKET_BLOCK = /(\[\#(\d+)\])/
          TAG_BLOCK = /(\[([^\]]+)\])/
          COMMENT_BLOCK = /\s*(.*)\s*/

          TAG_TICKET = /^\#(\d+)/
          TAG_PROP = /([a-z]+)/
          TAG_DIV = /\:/
          TAG_VALUE = /(("([^"]+)")|([^ ]+))/
          TAG_BLOCK_SCAN = /#{TAG_PROP}#{TAG_DIV}#{TAG_VALUE}/i

          SPLIT_FORMAT = /^\s*#{TICKET_BLOCK}#{COMMENT_BLOCK}#{TAG_BLOCK}/
          PRE_FORMAT = /^\s*#{TAG_BLOCK}#{COMMENT_BLOCK}/
          POST_FORMAT = /^\s*#{COMMENT_BLOCK}#{TAG_BLOCK}/

          # Yields a hash for each line which has a ticket reference
          def parse_log(log)
            log.each_line do |line|
              yield parse_line(line) if line =~ TICKET_REF
            end
          end
          
          # Returns a hash of the id, properties and content (comment)
          def parse_line(raw)
            return {} if raw.nil?
            if raw =~ SPLIT_FORMAT
              { :content => $3.strip, :id => $2 }.merge(extract_properties($5))
            elsif raw =~ PRE_FORMAT
              { :content => $3.strip }.merge(extract_properties($2))
            elsif raw =~ POST_FORMAT
              { :content => $1.strip }.merge(extract_properties($3))
            end
          end

          protected

          # Extracts an id if it is there and proceeds to extract properties
          def extract_properties(block)
            properties = block =~ TAG_TICKET ? { :id => $1 } : {}
            find_properties(block) { |prop, value| properties[prop] = value }
            properties
          end

          # Scans a block of tags and yields each property/value pair
          def find_properties(block)
            block.scan(TAG_BLOCK_SCAN) do
              prop, value = $1.to_sym, $2
              value = $1 if value =~ /^\"(.*)\"$/
              yield prop, value
            end
          end

        end
      end

    end # SCMTicketUpdate
  end
end